package com.ec.auth.interceptor;

import com.ec.common.utils.DateUtils;
import com.ec.common.utils.StringUtils;
import com.ec.auth.datasource.DynamicDataSourceContextHolder;
import com.ec.auth.datasource.DynamicRoutingDataSource;
import com.ec.saas.domain.MasterTenant;
import com.ec.saas.domain.enums.TenantStatus;
import com.ec.saas.service.IMasterTenantService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * 数据源拦截器
 * 一个http请求 先Filter后 处理 HTTPServlet
 * @author xxxx
 */

/**
 * 这个接口定义了拦截器在 Spring Web 应用程序中的执行阶段，允许开发者在请求处理的不同阶段添加自己的逻辑和功能
 * 接口HandlerInterceptor定义了三个方法，用于在 Spring Web 应用程序的请求处理过程中的不同阶段进行拦截和操作
 * preHandle用于在请求处理之前进行预处理
 * postHandle 这也是一个默认方法，在请求处理之后但在视图渲染之前执行 不常用 现在架构都是前后端分离
 * afterCompletion方法 同样是一个默认方法，在请求处理完成后执行，无论是否发生异常
 */
@Component
@Slf4j
public class TenantInterceptor implements HandlerInterceptor {

    /**
     * 租户的连接信息
     */
    @Autowired
    private IMasterTenantService masterTenantService;

    @Autowired
    private DynamicRoutingDataSource dynamicRoutingDataSource;

    @Value("${spring.datasource.driverClassName}")
    private String driverClassName;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String url = request.getServletPath();
        String tenant = request.getHeader("tenant");
        log.info("&&&&&&&&&&&&&&&& 租户拦截 &&&&&&&&&&&&&&&&");
        if (StringUtils.isNotBlank(tenant)) {
            if (!dynamicRoutingDataSource.existDataSource(tenant)) {
                //搜索默认数据库，去注册租户的数据源，下次进来直接session匹配数据源
                MasterTenant masterTenant = masterTenantService.selectMasterTenant(tenant);
                if (masterTenant == null) {
                    throw new RuntimeException("无此租户:" + tenant);
                } else if (TenantStatus.DISABLE.getCode().equals(masterTenant.getStatus())) {
                    throw new RuntimeException("租户[" + tenant + "]已停用");
                } else if (masterTenant.getExpirationDate() != null) {
                    if (masterTenant.getExpirationDate().before(DateUtils.getNowDate())) {
                        throw new RuntimeException("租户[" + tenant + "]已过期");
                    }
                }
                // 组装租户的数据源
                // 数据源的内容 password这里也可以进行加密解密
                Map<String, Object> map = new HashMap<>();
                map.put("driverClassName", driverClassName);
                map.put("url", masterTenant.getUrl());
                map.put("username", masterTenant.getUsername());
                map.put("password", masterTenant.getPassword());
                dynamicRoutingDataSource.addDataSource(tenant, map);

                log.info("&&&&&&&&&&& 已设置租户:{} 连接信息: {}", tenant, masterTenant);
            } else {
                log.info("&&&&&&&&&&& 当前租户:{}", tenant);
            }
        } else {
            // 如果没有租户字段
            throw new RuntimeException("缺少租户信息");
        }

        // 为了单次请求，多次连接数据库的情况，
        // 这里设置localThread，AbstractRoutingDataSource的方法去获取设置数据源
        DynamicDataSourceContextHolder.setDataSourceKey(tenant);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        // 请求结束删除localThread
        DynamicDataSourceContextHolder.clearDataSourceKey();
    }
}
